﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SMTP.Test.Client.Commands;
using Microsoft.Win32;
using System.IO;
using System.ComponentModel;
using System.Windows.Threading;
using Heijden.DNS;

namespace SMTP.Test.Client
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const string PROGRAM_NAME = "Mail Test Agent (MTA)";
        vmTestClient vm = new vmTestClient();

        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);

            //set command bindings
            //send email bindings
            CommandBinding SendEmailBinding = new CommandBinding(InterfaceCommands.SendEmail);
            SendEmailBinding.CanExecute += new CanExecuteRoutedEventHandler(SendEmailBinding_CanExecute);
            SendEmailBinding.Executed += new ExecutedRoutedEventHandler(SendEmailBinding_Executed);

            //save defaults bindings
            CommandBinding SaveDefualtsBinding = new CommandBinding(InterfaceCommands.SaveDefaults);
            SaveDefualtsBinding.CanExecute += new CanExecuteRoutedEventHandler(SaveDefualtsBinding_CanExecute);
            SaveDefualtsBinding.Executed += new ExecutedRoutedEventHandler(SaveDefualtsBinding_Executed);

            //save log data
            CommandBinding SaveLogFile = new CommandBinding(ApplicationCommands.Save);
            SaveLogFile.CanExecute += new CanExecuteRoutedEventHandler(SaveLogFile_CanExecute);
            SaveLogFile.Executed += new ExecutedRoutedEventHandler(SaveLogFile_Executed);

            //clear log data
            CommandBinding ClearLogFile = new CommandBinding(InterfaceCommands.ClearLog);
            ClearLogFile.CanExecute += new CanExecuteRoutedEventHandler(ClearLogFile_CanExecute);
            ClearLogFile.Executed += new ExecutedRoutedEventHandler(ClearLogFile_Executed);

            //scan port
            CommandBinding ScanPortBinding = new CommandBinding(InterfaceCommands.ScanPort);
            ScanPortBinding.CanExecute += new CanExecuteRoutedEventHandler(ScanPortBinding_CanExecute);
            ScanPortBinding.Executed += new ExecutedRoutedEventHandler(ScanPortBinding_Executed);

            //ping host
            CommandBinding PingHostBinding = new CommandBinding(InterfaceCommands.PingHost);
            PingHostBinding.CanExecute += new CanExecuteRoutedEventHandler(PingHostBinding_CanExecute);
            PingHostBinding.Executed += new ExecutedRoutedEventHandler(PingHostBinding_Executed);

            //ping host forever
            CommandBinding PingHostForeverBinding = new CommandBinding(InterfaceCommands.PingHostForever);
            PingHostForeverBinding.CanExecute += new CanExecuteRoutedEventHandler(PingHostForeverBinding_CanExecute);
            PingHostForeverBinding.Executed += new ExecutedRoutedEventHandler(PingHostForeverBinding_Executed);
           
            //cancellation
            CommandBinding CancelRequestBinding = new CommandBinding(InterfaceCommands.CancelRequest);
            CancelRequestBinding.CanExecute += new CanExecuteRoutedEventHandler(CancelRequestBinding_CanExecute);
            CancelRequestBinding.Executed += new ExecutedRoutedEventHandler(CancelRequestBinding_Executed);

            //dns MX records
            CommandBinding DNS_MXRecordBinding = new CommandBinding(InterfaceCommands.DNS_MXRecords);
            DNS_MXRecordBinding.CanExecute += new CanExecuteRoutedEventHandler(DNS_MXRecordBinding_CanExecute);
            DNS_MXRecordBinding.Executed += new ExecutedRoutedEventHandler(DNS_MXRecordBinding_Executed);

            //dns A records
            CommandBinding DNS_ARecordBinding = new CommandBinding(InterfaceCommands.DNS_ARecords);
            DNS_ARecordBinding.CanExecute += new CanExecuteRoutedEventHandler(DNS_ARecordBinding_CanExecute);
            DNS_ARecordBinding.Executed += new ExecutedRoutedEventHandler(DNS_ARecordBinding_Executed);

            //dns CNAME records
            CommandBinding DNS_CNAMERecordBinding = new CommandBinding(InterfaceCommands.DNS_CNAMERecords);
            DNS_CNAMERecordBinding.CanExecute += new CanExecuteRoutedEventHandler(DNS_CNAMERecordBinding_CanExecute);
            DNS_CNAMERecordBinding.Executed += new ExecutedRoutedEventHandler(DNS_CNAMERecordBinding_Executed);

            //add attachment
            CommandBinding AddAttachment = new CommandBinding(InterfaceCommands.AddAttachment);
            AddAttachment.CanExecute += new CanExecuteRoutedEventHandler(AddAttachment_CanExecute);
            AddAttachment.Executed += new ExecutedRoutedEventHandler(AddAttachment_Executed);

            //clear attchment
            CommandBinding ClearAttachment = new CommandBinding(InterfaceCommands.ClearAttachment);
            ClearAttachment.CanExecute += new CanExecuteRoutedEventHandler(ClearAttachment_CanExecute);
            ClearAttachment.Executed += new ExecutedRoutedEventHandler(ClearAttachment_Executed);

            //register with wpf form
            this.CommandBindings.Add(SendEmailBinding);
            this.CommandBindings.Add(SaveDefualtsBinding);
            this.CommandBindings.Add(SaveLogFile);
            this.CommandBindings.Add(ClearLogFile);
            this.CommandBindings.Add(ScanPortBinding);
            this.CommandBindings.Add(PingHostBinding);
            this.CommandBindings.Add(PingHostForeverBinding);
            this.CommandBindings.Add(CancelRequestBinding);
            this.CommandBindings.Add(DNS_MXRecordBinding);
            this.CommandBindings.Add(DNS_ARecordBinding);
            this.CommandBindings.Add(DNS_CNAMERecordBinding);
            this.CommandBindings.Add(AddAttachment);
            this.CommandBindings.Add(ClearAttachment);

            //place versioning info in title
            Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            this.Title += " -- v" + v.Major.ToString() + "." + v.Minor.ToString() + "." + v.Build.ToString() + "";
        }

        void ClearAttachment_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.Attachment = "";
        }

        void ClearAttachment_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                if (vm.Attachment.Length > 0)
                {
                    e.CanExecute = true;
                }
                else
                {
                    e.CanExecute = false;
                }
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void AddAttachment_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Add Attachment";
            ofd.Multiselect = false;
            ofd.Filter = "All Files|*.*";

            if (ofd.ShowDialog() == true)
            {
                vm.Attachment = ofd.FileName;
            }
        }

        void AddAttachment_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                if (vm.Attachment.Length > 0)
                {
                    e.CanExecute = false;
                }
                else
                {
                    e.CanExecute = true;
                }
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void DNS_CNAMERecordBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ComboDNSCommands.SelectedIndex = 1;
            vm.DNSLookup(QType.CNAME, QClass.ANY);
        }

        void DNS_CNAMERecordBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void DNS_ARecordBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ComboDNSCommands.SelectedIndex = 0;
            vm.DNSLookup(QType.A, QClass.ANY);
        }

        void DNS_ARecordBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void DNS_MXRecordBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ComboDNSCommands.SelectedIndex = 2;           
            vm.DNSLookup(QType.MX, QClass.ANY);
        }

        void DNS_MXRecordBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void PingHostForeverBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.SaveNotes(TextLog.Text);
            ComboPingCommands.SelectedIndex = 1;
            vm.PingHostForever();
        }

        void PingHostForeverBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void CancelRequestBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.CancelTask();
        }

        void CancelRequestBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (vm.RunningRequest)
            {
                if ((vm.CancellationPermitted) && (!vm.CancellationInitiated))
                {
                    e.CanExecute = true;
                }
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void PingHostBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.SaveNotes(TextLog.Text);
            ComboPingCommands.SelectedIndex = 0;
            vm.PingHost();
        }

        void PingHostBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void ScanPortBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.SaveNotes(TextLog.Text);
            vm.AddSessionLogEntry("Begin scanning port " + vm.Port + " on host " + vm.Server);
            vm.ScanPort();
        }

        void ScanPortBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void ClearLogFile_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            vm.SaveNotes(TextLog.Text);
            vm.ClearSessionLog();
        }

        void ClearLogFile_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void SaveLogFile_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            try
            {
                vm.SaveNotes(TextLog.Text);
                SaveFileDialog sf = new SaveFileDialog();
                sf.DefaultExt = ".log";
                sf.Title = PROGRAM_NAME + " - Save log file";
                sf.Filter = "Log (*.log)|*.log|All Files|*.*";

                if (sf.ShowDialog() == true)
                {
                    StreamWriter w = new StreamWriter(sf.FileName);
                    w.Write(vm.SessionLog);
                    w.Close();
                    MessageBox.Show("Log saved", PROGRAM_NAME);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error saving log file: \r\n" + ex.Message, PROGRAM_NAME);
            }
        }

        void SaveLogFile_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!vm.RunningRequest)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        void SaveDefualtsBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            try
            {
                string strPort = "0";
                int intPort = 0;

                if (Int32.TryParse(TextPort.Text.Trim(), out intPort))
                {
                    strPort = TextPort.Text.Trim();
                }
                
                Properties.Settings.Default.DefaultServer = TextServer.Text.Trim();
                Properties.Settings.Default.DefaultPort = strPort;
                Properties.Settings.Default.DefaultTo = TextTo.Text.Trim();
                Properties.Settings.Default.DefaultFrom = TextFrom.Text.Trim();
                Properties.Settings.Default.DefaultSubject = TextSubject.Text.Trim();
                Properties.Settings.Default.DefaultBody = TextBody.Text.Trim();
                Properties.Settings.Default.Save();
                System.Windows.MessageBox.Show("Defaults saved", PROGRAM_NAME);
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("An error occurred saving defaults:\r\n" + ex.Message, PROGRAM_NAME);
            }
        }

        void SaveDefualtsBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (vm.RunningRequest)
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
        }

        void SendEmailBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //ensure we save notes
            vm.SaveNotes(TextLog.Text);
            //WPF Password has no dependency property for password property
            vm.Password = UserPassword.Password;
            vm.SendMail();
        }

        void SendEmailBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (vm.RunningRequest)
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            vm.RequestComplete += new EventHandler(vm_RequestComplete);
            this.DataContext = vm;
            LoadDefaults();
            vm.AddSessionLogEntry(PROGRAM_NAME + " started");
        }


        void vm_RequestComplete(object sender, EventArgs e)
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
            {
                //force RequerySuggested event to fire, which will cause ICommand to run CanExecute
                CommandManager.InvalidateRequerySuggested();

                //request complete may finish before processing of all response data
                //make sure that we scroll to the end
                TextLog.ScrollToEnd();
            });
        }

        void LoadDefaults()
        {
            vm.Server = Properties.Settings.Default.DefaultServer;
            vm.Port = Properties.Settings.Default.DefaultPort;
            vm.To = Properties.Settings.Default.DefaultTo;
            vm.From = Properties.Settings.Default.DefaultFrom;
            vm.Subject = Properties.Settings.Default.DefaultSubject;
            vm.Body = Properties.Settings.Default.DefaultBody;
        }

        private void TextLog_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (vm.RunningRequest)
            {
                TextLog.ScrollToEnd();
            }
        }
    }
}
